home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Games / NeXTGo / Source / Board.m < prev    next >
Text File  |  1993-02-08  |  42KB  |  1,849 lines

  1. #include "comment.header"
  2.  
  3. #import "Board.h"
  4. #import "gnugo.h"
  5. #include "igs.h"
  6.  
  7. #import <libc.h>
  8. #import <math.h>
  9. #import <dpsclient/wraps.h>    // PSxxx functions
  10. #import <soundkit/Sound.h>
  11. #import <appkit/appkit.h>
  12.  
  13. #define EMPTY        0
  14. #define WHITESTONE    1
  15. #define BLACKSTONE    2
  16. #define NEUTRAL_TERR    3
  17. #define WHITE_TERR    4
  18. #define BLACK_TERR    5
  19. #define SPECIAL_CHAR    6
  20. #define KOMI            5.5
  21.  
  22. // The following values are the default sizes for the various pieces. 
  23.   
  24. #define RADIUS        14.5             // Stone radius
  25. #define STONEWIDTH    29.0            // Stone width
  26. #define STONEHEIGHT    29.0            // Stone height
  27.   
  28.   // SHADOWOFFSET defines the amount the shadow is offset from the piece. 
  29.   
  30. #define SHADOWOFFSET 2.0
  31.   
  32. #define BASEBOARDX 19.0
  33. #define BASEBOARDY 19.0
  34. #define WINDOWOFFSETX 12.0
  35. #define WINDOWOFFSETY 100.0
  36.   
  37. #define gameSize  bounds.size
  38.  
  39. #define PSLine(a, b, x, y)    PSmoveto(a, b); PSlineto(x, y)
  40.  
  41. float stoneX, stoneY;
  42. int blackStones, whiteStones;
  43. char currentCharacter;
  44.  
  45. void setStoneLoc(int x, int y)
  46. {
  47.   stoneX = ((19.0 - MAXX)/2.0)*STONEWIDTH + BASEBOARDX - RADIUS + (x*STONEWIDTH);
  48.   stoneY = BASEBOARDY - RADIUS + ((18 - y)*STONEHEIGHT) - ((19.0 - MAXY)/2.0)*STONEHEIGHT;
  49. }  
  50.  
  51. @implementation GoView
  52.   
  53.   - initFrame:(const NXRect *)frm
  54. {
  55.   NXSize stoneSize;
  56.   
  57.   stoneSize.width = STONEWIDTH;
  58.   stoneSize.height = STONEHEIGHT;
  59.   
  60.   [super initFrame:frm];
  61.   
  62.   [self allocateGState];    // For faster lock/unlockFocus
  63.     
  64.   [(blackStone = [[NXImage allocFromZone:[self zone]] init]) setScalable:NO];
  65.   [blackStone useDrawMethod:@selector(drawBlackStone:) inObject:self];
  66.   [blackStone setSize:&stoneSize];
  67.   
  68.   [(whiteStone = [[NXImage allocFromZone:[self zone]] init]) setScalable:NO];
  69.   [whiteStone useDrawMethod:@selector(drawWhiteStone:) inObject:self];
  70.   [whiteStone setSize:&stoneSize];
  71.   
  72.   [(grayStone = [[NXImage allocFromZone:[self zone]] init]) setScalable:NO];
  73.   [grayStone useDrawMethod:@selector(drawGrayStone:) inObject:self];
  74.   [grayStone setSize:&stoneSize];
  75.   
  76.   [(upperLeft = [[NXImage allocFromZone:[self zone]] init]) setScalable:NO];
  77.   [upperLeft useDrawMethod:@selector(drawUpperLeft:) inObject:self];
  78.   [upperLeft setSize:&stoneSize];
  79.   
  80.   [(upperRight = [[NXImage allocFromZone:[self zone]] init]) setScalable:NO];
  81.   [upperRight useDrawMethod:@selector(drawUpperRight:) inObject:self];
  82.   [upperRight setSize:&stoneSize];
  83.   
  84.   [(lowerLeft = [[NXImage allocFromZone:[self zone]] init]) setScalable:NO];
  85.   [lowerLeft useDrawMethod:@selector(drawLowerLeft:) inObject:self];
  86.   [lowerLeft setSize:&stoneSize];
  87.   
  88.   [(lowerRight = [[NXImage allocFromZone:[self zone]] init]) setScalable:NO];
  89.   [lowerRight useDrawMethod:@selector(drawLowerRight:) inObject:self];
  90.   [lowerRight setSize:&stoneSize];
  91.   
  92.   [(midLeft = [[NXImage allocFromZone:[self zone]] init]) setScalable:NO];
  93.   [midLeft useDrawMethod:@selector(drawMidLeft:) inObject:self];
  94.   [midLeft setSize:&stoneSize];
  95.   
  96.   [(midRight = [[NXImage allocFromZone:[self zone]] init]) setScalable:NO];
  97.   [midRight useDrawMethod:@selector(drawMidRight:) inObject:self];
  98.   [midRight setSize:&stoneSize];
  99.   
  100.   [(midTop = [[NXImage allocFromZone:[self zone]] init]) setScalable:NO];
  101.   [midTop useDrawMethod:@selector(drawMidTop:) inObject:self];
  102.   [midTop setSize:&stoneSize];
  103.   
  104.   [(midBottom = [[NXImage allocFromZone:[self zone]] init]) setScalable:NO];
  105.   [midBottom useDrawMethod:@selector(drawMidBottom:) inObject:self];
  106.   [midBottom setSize:&stoneSize];
  107.   
  108.   [(innerSquare = [[NXImage allocFromZone:[self zone]] init]) setScalable:NO];
  109.   [innerSquare useDrawMethod:@selector(drawInnerSquare:) inObject:self];
  110.   [innerSquare setSize:&stoneSize];
  111.   
  112.   [(innerHandicap = [[NXImage allocFromZone:[self zone]] init]) setScalable:NO];
  113.   [innerHandicap useDrawMethod:@selector(drawInnerHandicap:) inObject:self];
  114.   [innerHandicap setSize:&stoneSize];
  115.   
  116.   [self setBackgroundFile:NXGetDefaultValue([NXApp appName], "BackGround") 
  117.  andRemember:NO];
  118.   
  119.   [self startNewGame];
  120.  
  121.   historyFont = [Font newFont:"Helvetica" size:9.0 matrix:NX_IDENTITYMATRIX];
  122.   blackTerrFont = [Font newFont:"Helvetica" size:25.0 matrix:NX_IDENTITYMATRIX];
  123.   whiteTerrFont = [Font newFont:"Helvetica" size:22.5 matrix:NX_IDENTITYMATRIX];
  124.   stoneClick = [Sound findSoundFor:"Pop"];
  125.   
  126.   return self;
  127. }
  128.  
  129. // free simply gets rid of everything we created for MainGoView, including
  130.   // the instance of MainGoView itself. This is how nice objects clean up.
  131.   
  132.   - free
  133. {
  134.   [backGround free];
  135.   return [super free];
  136. }
  137.  
  138.  
  139.  
  140. // This methods allows changing the file used to paint the background of the
  141.   // playing field. Set fileName to NULL to revert to the default. Set
  142.   // remember to YES if you wish the write the value out in the defaults.
  143.   
  144.   - setBackgroundFile:(const char *)fileName andRemember:(BOOL)remember
  145. {
  146.   [backGround free];
  147.   backGround = [[NXImage allocFromZone:[self zone]] initSize:&gameSize];
  148.   if (fileName) {
  149.     [backGround useFromFile:fileName];
  150.     if (remember) {
  151.       NXWriteDefault ([NXApp appName], "Background", fileName);
  152.     }
  153.   } else {
  154.     [backGround useFromSection:"Background.tiff"];
  155.     if (remember) {
  156.       NXRemoveDefault ([NXApp appName], "Background");
  157.     }
  158.   }
  159.   [backGround setBackgroundColor:NX_COLORWHITE];
  160.   [backGround setScalable:NO];
  161.   [self display];
  162.   
  163.   return self;   
  164. }
  165.  
  166. // The following two methods allow changing the background image from
  167.   // menu items or buttons.
  168.   
  169.   - changeBackground:sender
  170. {
  171.   const char *const types[] = {"tiff", "eps", NULL};  
  172.   
  173.   if ([[OpenPanel new] runModalForTypes:types]) {
  174.     [self setBackgroundFile:[[OpenPanel new] filename] andRemember:YES];
  175.     [self display];
  176.   }
  177.   
  178.   return self;
  179. }
  180.  
  181. - revertBackground:sender
  182. {
  183.   [self setBackgroundFile:NULL andRemember:YES];
  184.   [self display];
  185.   return self;
  186. }
  187.  
  188. // The following method will initialize all the variables for a new game.
  189.   
  190.   - startNewGame
  191. {
  192.   int i, j;
  193.   
  194.   gameRunning = NO;
  195.   finished = NO;
  196.   gameScored = NO;
  197.   resultsDisplayed = NO;
  198.   scoringGame = NO;
  199.  
  200.   lastMove = 0;
  201.   
  202.   blackCaptured = whiteCaptured = 0;
  203.   manualScoring = manScoreTemp;
  204.   
  205.   seed(&rd);
  206.   
  207.   for (i = 0; i < MAXX; i++)
  208.     for (j = 0; j < MAXY; j++)
  209.       p[i][j] = hist[i][j] = 0;
  210.   
  211.   for (i = 0; i < 9; i++)
  212.     opn[i] = 1;
  213.   opn[4] = 0;
  214.  
  215.   if (gameType == LOCAL)
  216.     {
  217.       sethand(handicap);
  218.       currentStone = (handicap == 0)?BLACKSTONE:WHITESTONE;
  219.       opposingStone = (currentStone == BLACKSTONE)?WHITESTONE:BLACKSTONE;
  220.   
  221.       if (currentStone == BLACKSTONE)
  222.     [gameMessage setStringValue:"Black's Turn"];
  223.       else
  224.     [gameMessage setStringValue:"White's Turn"];
  225.  
  226.       if (SmartGoGameFlag)
  227.     {
  228.       [startButton setEnabled: NO];
  229.       [stopButton setEnabled: NO];
  230.       [passButton setEnabled: NO];
  231.       [startButton display];
  232.       [stopButton display];
  233.       [passButton display];
  234.     }
  235.     
  236.       if (bothSides)
  237.     [passButton setEnabled: NO];
  238.       else
  239.     [passButton setEnabled: YES];
  240.       [passButton display];
  241.   
  242.       if (neitherSide) {
  243.     [startButton setEnabled: NO];
  244.     [stopButton setEnabled: NO];
  245.     [startButton display];
  246.     [stopButton display];
  247.       } else {
  248.     [startButton setEnabled: YES];
  249.     [stopButton setEnabled: YES];
  250.     [startButton display];
  251.     [stopButton display];
  252.       }
  253.   
  254.       if (((currentStone == BLACKSTONE) && (blackSide == 1)) ||
  255.       ((currentStone == WHITESTONE) && (whiteSide == 1)))  
  256.     [gameMessage2 setStringValue:"Press START to begin..."];
  257.       else
  258.     [gameMessage2 setStringValue:"You move first..."];
  259.       [self setblacksPrisoners:0];
  260.       [self setwhitesPrisoners:0];
  261.     }
  262.   else
  263.     {
  264.       [gameMessage2 setStringValue:"Internet Go Server"];
  265.       [gameMessage setStringValue:""];
  266.       [self setblacksPrisoners:0];
  267.       [self setwhitesPrisoners:0];
  268.       [passButton setEnabled: YES];
  269.       [startButton setEnabled: NO];
  270.       [stopButton setEnabled: NO];
  271.       [passButton display];
  272.       [startButton display];
  273.       [stopButton display];
  274.     }
  275.     
  276.   [ScoringWindow close];
  277.   NXPing();
  278.     
  279.   return self;
  280. }
  281.  
  282. // The stop method will pause a running game. The go method will start it up
  283.   // again.
  284.   
  285. - go:sender
  286. {
  287.   if (gameType == IGSGAME)
  288.     return self;
  289.     
  290.   if ((scoringGame) && (manualScoring))
  291.     {
  292.       int i, j;
  293.  
  294.       find_owner();
  295.       blackTerritory = 0;
  296.       whiteTerritory = 0;
  297.  
  298.       for (i = 0; i < MAXX; i++)
  299.     for (j = 0; j < MAXY; j++)
  300.       {
  301.         if (ownermat[i][j] == BLACKSTONE)
  302.           {
  303.         blackTerritory++;
  304.         p[i][j] = BLACK_TERR;
  305.           }
  306.         if (ownermat[i][j] == WHITESTONE)
  307.           {
  308.         whiteTerritory++;
  309.         p[i][j] = WHITE_TERR;
  310.           }
  311.         if (ownermat[i][j] == NEUTRAL_TERR)
  312.           {
  313.         p[i][j] = NEUTRAL_TERR;
  314.           }
  315.       }
  316.  
  317.       gameScored = YES;
  318.       [self displayScoringInfo];
  319.       NXPing();
  320.     }
  321.  
  322.   if ((gameRunning == 0) && (finished == 0)) {
  323.     gameRunning = YES;
  324.     [self step];
  325.   }
  326.   return 0;
  327. }
  328.  
  329. - stop:sender
  330. {
  331.   if (gameType == IGSGAME)
  332.     return self;
  333.       
  334.   if (gameRunning) {
  335.     gameRunning = NO;
  336.   }
  337.   return self;
  338. }
  339.  
  340. - showLastMove:sender
  341. {
  342.   if (SmartGoGameFlag)
  343.     return self;
  344.  
  345.   if (finished)
  346.     {
  347.       NXRunAlertPanel("NeXTGo", "The game has concluded.  The last move was\n\
  348. the scoring.", "OK", 0, 0);
  349.  
  350.       return self;
  351.     }
  352.  
  353.   if (lastMove == 0)
  354.     {
  355.       NXRunAlertPanel("NeXTGo", "The game has not yet started.", "OK", 0, 0);
  356.  
  357.       return self;
  358.     }
  359.  
  360.   if (gameMoves[lastMove-1].x < 0)
  361.     {
  362.       NXRunAlertPanel("NeXTGo", "The last move was a pass.", "OK", 0, 0);
  363.  
  364.       return self;
  365.     }
  366.     
  367.   setStoneLoc(gameMoves[lastMove-1].x, gameMoves[lastMove-1].y);
  368.   [self lockFocus];
  369.   [self showGrayStone];
  370.   [self unlockFocus];
  371.   NXPing();
  372.   
  373.   [self lockFocus];
  374.   [[self window] flushWindow];
  375.   [self drawSelf:&bounds :0];
  376.   [self display];
  377.   [self unlockFocus];
  378.   NXPing();
  379.   
  380.   return self;
  381. }
  382.  
  383. - undo
  384. {
  385.   int i, j;
  386.  
  387.   if (finished)
  388.     return self;
  389.   
  390.   if (lastMove == 1)
  391.     {
  392.       [self startNewGame];
  393.       [self display];
  394.  
  395.       return self;
  396.     }
  397.     
  398.   if (lastMove > 0)
  399.     {
  400.       for (i = 0; i < MAXX; i++)
  401.     for (j = 0; j < MAXY; j++)
  402.       p[i][j] = 0;
  403.       blackCaptured = 0;
  404.       whiteCaptured = 0;
  405.  
  406.       lastMove--;
  407.  
  408.       for (i = 0; i < lastMove; i++)
  409.     {
  410.       if (gameMoves[i].x >= 0)
  411.         {
  412.           blackPassed = whitePassed = 0;
  413.           p[gameMoves[i].x][gameMoves[i].y] = gameMoves[i].color;
  414.  
  415.           currentStone = gameMoves[i].color;
  416.           opposingStone = (currentStone == BLACKSTONE)?WHITESTONE
  417.         :BLACKSTONE;
  418.           examboard(opposingStone);
  419.         }
  420.       else
  421.         {
  422.           blackPassed = (gameMoves[i].color == BLACKSTONE)?1:0;
  423.           whitePassed = (gameMoves[i].color == WHITESTONE)?1:0;
  424.         }
  425.     }
  426.       [self refreshIO];
  427.  
  428.       currentStone = opposingStone;
  429.       opposingStone = (currentStone == BLACKSTONE)?WHITESTONE:BLACKSTONE;
  430.  
  431.       if (gameType == LOCAL)
  432.     {
  433.       [gameMessage setStringValue:(currentStone == BLACKSTONE)?
  434.        "Black's Turn":"White's Turn"];
  435.       
  436.       if ((bothSides) || (((currentStone == BLACKSTONE) && (blackSide)) ||
  437.                   ((currentStone == WHITESTONE) && (whiteSide))))
  438.         {
  439.           [gameMessage2 setStringValue:"Press START to continue..."];
  440.           gameRunning = 0;
  441.         }
  442.       else
  443.         [gameMessage2 setStringValue:"Your move..."];
  444.     }
  445.     }
  446.  
  447.   return self;
  448. }
  449.  
  450. - undoLastMove:sender
  451. {
  452.   if (SmartGoGameFlag)
  453.     return self;
  454.  
  455.   if (gameType == LOCAL)
  456.     {
  457.       [self undo];
  458.     }
  459.   else
  460.     {
  461.       sendstr("undo\n");
  462.     }
  463.  
  464.   return self;
  465. }
  466.  
  467. - toggleShowHistFlag:sender
  468. {
  469.   if (SmartGoGameFlag)
  470.     return self;
  471.  
  472.   [self lockFocus];
  473.   [self display];
  474.   [self unlockFocus];
  475.  
  476.   return self;
  477. }
  478.  
  479. - toggleSound:sender
  480. {
  481.  
  482.   return self;
  483. }
  484.  
  485. - toggleCoords:sender
  486. {
  487.   [self lockFocus];
  488.   [self display];
  489.   [self unlockFocus];
  490.  
  491.   return self;
  492. }
  493.  
  494. - mouseDown:(NXEvent *)event
  495. {
  496.   NXPoint pickedP;
  497.  
  498.   if (gameType == LOCAL)
  499.     {
  500.       if ((((currentStone == BLACKSTONE) && (blackSide == 1)) ||
  501.        ((currentStone == WHITESTONE) && (whiteSide == 1))) &&
  502.       (!scoringGame) && (!manualScoring))
  503.     return self;
  504.  
  505.       if (SmartGoGameFlag)
  506.     return self;
  507.     
  508.       if ((!gameRunning) && (!finished))
  509.     gameRunning = YES;
  510.   
  511.       if (!finished) {
  512.     int x, y;
  513.  
  514.     pickedP = event->location;
  515.     
  516.     x = floor((pickedP.x - ((19.0 - MAXX)/2.0)*STONEWIDTH - BASEBOARDX -
  517.            WINDOWOFFSETX + RADIUS)/STONEWIDTH);
  518.     y = 18 - floor((pickedP.y - BASEBOARDY - WINDOWOFFSETY + RADIUS +
  519.             ((19.0 - MAXY)/2.0)*STONEHEIGHT)/STONEHEIGHT);
  520.     
  521.     if (x < 0) x = 0;
  522.     if (x > MAXX - 1) x = MAXX - 1;
  523.     if (y < 0) y = 0;
  524.     if (y > MAXY - 1) y = MAXY - 1;
  525.     
  526.     if ((p[x][y] == 0) && (!suicide(x,y))) {
  527.       p[x][y] = currentStone;
  528.       if (currentStone == BLACKSTONE)
  529.         blackPassed = 0;
  530.       else
  531.         whitePassed = 0;
  532.  
  533.       [self addMoveToGameMoves: currentStone: x: y];
  534.       
  535.       setStoneLoc(x,y);
  536.       
  537.       [self lockFocus];
  538.       switch (p[x][y])
  539.         {
  540.         case WHITESTONE: [self showWhiteStone];
  541.           break;
  542.         case BLACKSTONE: [self showBlackStone];
  543.           break;
  544.         default: break;
  545.         }
  546.       [self unlockFocus];
  547.  
  548.       if ([playSounds intValue])
  549.         [stoneClick play];
  550.       NXPing();
  551.  
  552.       [self updateInfo];
  553.  
  554.       if (!neitherSide)
  555.         [self step];
  556.     } 
  557.       } else {
  558.     if ((scoringGame) && (manualScoring) && (!gameScored))
  559.       {
  560.         int x, y;
  561.  
  562.         pickedP = event->location;
  563.     
  564.         x = floor((pickedP.x - ((19.0 - MAXX)/2.0)*STONEWIDTH - BASEBOARDX
  565.                - WINDOWOFFSETX + RADIUS)/STONEWIDTH);
  566.         y = 18 - floor((pickedP.y - BASEBOARDY - WINDOWOFFSETY + RADIUS +
  567.                 ((19.0 - MAXY)/2.0)*STONEHEIGHT)/STONEHEIGHT);
  568.     
  569.         if (x < 0) x = 0;
  570.         if (x > MAXX - 1) x = MAXX - 1;
  571.         if (y < 0) y = 0;
  572.         if (y > MAXY - 1) y = MAXY - 1;
  573.  
  574.         if (p[x][y] != EMPTY)
  575.           {
  576.         int k, l;
  577.  
  578.         currentStone = p[x][y];
  579.  
  580.         find_pattern_in_board(x, y);
  581.         for (k = 0; k < MAXX; k++)
  582.           for (l = 0; l < MAXY; l++)
  583.             if (patternmat[k][l])
  584.               {
  585.             p[k][l] = EMPTY;
  586.             if (currentStone == BLACKSTONE)
  587.               blackCaptured++;
  588.             else
  589.               whiteCaptured++;
  590.               }
  591.         
  592.         [self setblacksPrisoners:blackCaptured];
  593.         [self setwhitesPrisoners:whiteCaptured];
  594.  
  595.                 [self lockFocus];
  596.         [self display];
  597.         [self unlockFocus];
  598.           }
  599.       }
  600.       }
  601.     }
  602.   else
  603.     {
  604.       int x, y;
  605.       char s[5], n[5];
  606.       extern int observing, ingame;
  607.  
  608.       if (observing || (ingame == -1))
  609.     {
  610.       NXRunAlertPanel("IGS Error", "You cannot make a move unless you are playing.",
  611.               "OK", 0, 0);
  612.  
  613.       return self;
  614.     }
  615.  
  616.       pickedP = event->location;
  617.     
  618.       x = floor((pickedP.x - ((19.0 - MAXX)/2.0)*STONEWIDTH - BASEBOARDX -
  619.          WINDOWOFFSETX + RADIUS)/STONEWIDTH);
  620.       y = 18 - floor((pickedP.y - BASEBOARDY - WINDOWOFFSETY + RADIUS +
  621.               ((19.0 - MAXY)/2.0)*STONEHEIGHT)/STONEHEIGHT);
  622.  
  623.       if (x < 0) x = 0;
  624.       if (x > MAXX - 1) x = MAXX - 1;
  625.       if (y < 0) y = 0;
  626.       if (y > MAXY - 1) y = MAXY - 1;
  627.  
  628.       s[0] = x + 'a';
  629.       if (x > 7)
  630.         s[0] = x + 'b';
  631.       s[1] = 0;
  632.       sprintf(n, "%d", MAXY-y);
  633.       strcat(s, n);
  634.       strcat(s, "\n");
  635.  
  636.       sendstr(s);
  637.     }
  638.  
  639.   return self;
  640. }
  641.  
  642. - passMove
  643. {
  644.   if (gameType == LOCAL)
  645.     {
  646.       if (((currentStone == BLACKSTONE) && (blackSide == 1)) ||
  647.       ((currentStone == WHITESTONE) && (whiteSide == 1)))
  648.     return self;
  649.  
  650.       if (currentStone == BLACKSTONE)
  651.     {
  652.       blackPassed = 1;
  653.       if (AGAScoring) blackCaptured++;
  654.     }
  655.       else
  656.     {
  657.       whitePassed = 1;
  658.       if (AGAScoring) whiteCaptured++;
  659.     }
  660.  
  661.       [self addMoveToGameMoves: currentStone: -1: -1];
  662.     
  663.       [self updateInfo];
  664.       if ((!neitherSide) && (!finished))
  665.     [self step];
  666.     }
  667.   else
  668.     {
  669.       sendstr("pass\n");
  670.     }
  671.     
  672.   return self;
  673. }
  674.  
  675. - refreshIO
  676. {
  677.   [self setblacksPrisoners:blackCaptured];
  678.   [self setwhitesPrisoners:whiteCaptured];
  679.   
  680.   [self lockFocus];
  681.   [[self window] flushWindow];
  682.   [self drawSelf:&bounds :0];
  683.   [self display];
  684.   [self unlockFocus];
  685.   
  686.   NXPing();
  687.  
  688.   return self;
  689. }
  690.  
  691. - addMoveToGameMoves: (int)color: (int)x: (int)y
  692. {
  693.   gameMoves[lastMove].color = color;
  694.   gameMoves[lastMove].x = x;
  695.   gameMoves[lastMove].y = y;
  696.   lastMove++;
  697.  
  698.   if (x >= 0)
  699.     hist[x][y] = lastMove;
  700.  
  701.   return self;
  702. }
  703.  
  704. - makeMove: (int)color: (int)x: (int)y
  705. {
  706.   int oldwhitesPrisoners, oldblacksPrisoners, i, j;
  707.   unsigned char old_Board[19][19];
  708.  
  709.   [self addMoveToGameMoves: color: x: y];
  710.  
  711.   if ((x >= 0) && (y >= 0))
  712.     {
  713.       p[x][y] = color;
  714.       
  715.       setStoneLoc(x,y);
  716.  
  717.       [self lockFocus];
  718.       switch (p[x][y])
  719.         {
  720.         case WHITESTONE: [self showWhiteStone];
  721.           break;
  722.         case BLACKSTONE: [self showBlackStone];
  723.           break;
  724.         default: break;
  725.         }
  726.       [self unlockFocus];
  727.  
  728.       if ([playSounds intValue])
  729.         [stoneClick play];
  730.       NXPing();
  731.  
  732.       currentStone = color;
  733.       opposingStone = (currentStone == BLACKSTONE)?WHITESTONE:BLACKSTONE;
  734.  
  735.       oldblacksPrisoners = blackCaptured;
  736.       oldwhitesPrisoners = whiteCaptured;
  737.       for (i = 0; i < MAXX; i++)
  738.         for (j = 0; j < MAXX; j++)
  739.           old_Board[i][j] = p[i][j];
  740.       
  741.       examboard(opposingStone);
  742.   
  743.       [gameMessage setStringValue:(opposingStone == BLACKSTONE)?"Black's Turn":
  744.        "White's Turn"];
  745.       [self setblacksPrisoners:blackCaptured];
  746.       [self setwhitesPrisoners:whiteCaptured];
  747.   
  748.       if (((oldblacksPrisoners != blackCaptured) ||
  749.            (oldwhitesPrisoners != whiteCaptured)))
  750.         {
  751.           [self lockFocus];
  752.       [self display];
  753.           [self unlockFocus];
  754.         }
  755.  
  756.       if ([showHistFlag intValue])
  757.         {
  758.           NXRect tmpRect = {{floor(stoneX), floor(stoneY)},
  759.                       {floor(STONEWIDTH), floor(STONEHEIGHT)}};
  760.  
  761.           [self lockFocus];
  762.           [self drawSelf:&tmpRect :0];
  763.           [self display];
  764.           [self unlockFocus];
  765.         }
  766.     }
  767.  
  768.   return self;
  769. }
  770.  
  771. - makeMoveSilent: (int)color: (int)x: (int)y
  772. {
  773.   [self addMoveToGameMoves: color: x: y];
  774.       
  775.   if ((x >= 0) && (y >= 0))
  776.     {
  777.       p[x][y] = color;
  778.  
  779.       currentStone = color;
  780.       opposingStone = (currentStone == BLACKSTONE)?WHITESTONE:BLACKSTONE;
  781.  
  782.       examboard(opposingStone);
  783.     }
  784.   
  785.   return self;
  786. }
  787.  
  788. - dispTime: (int)btime: (int)bbyo: (int)wtime: (int)wbyo
  789. {
  790.   char bltime[25], whtime[25];
  791.  
  792.   if (btime != -1)
  793.     {
  794.       if (btime < 0)
  795.     btime = 0;
  796.       if (wtime < 0)
  797.     wtime = 0;
  798.       sprintf(bltime, "%d:%02d", btime / 60, btime % 60);
  799.       if (bbyo != -1)
  800.     sprintf(bltime, "%s, %d", bltime, bbyo);
  801.       sprintf(whtime, "%d:%02d", wtime / 60, wtime % 60);
  802.       if (wbyo != -1)
  803.     sprintf(whtime, "%s, %d", whtime, wbyo);
  804.       [blackTime setStringValue:bltime];
  805.       [blackTime display];
  806.       [whiteTime setStringValue:whtime];
  807.       [whiteTime display];
  808.     }
  809.  
  810.   return self;
  811. }
  812.  
  813. - setGameNumber: (int)n
  814. {
  815.   [IGSGameNumber setIntValue:n];
  816.   [IGSGameNumber display];
  817.   
  818.   return self;
  819. }
  820.  
  821. - setWhiteName: (char *)wname
  822. {
  823.   [IGSWhitePlayer setStringValue:wname];
  824.   [IGSWhitePlayer display];
  825.   
  826.   return self;
  827. }
  828.  
  829. - setBlackName: (char *)bname
  830. {
  831.   [IGSBlackPlayer setStringValue:bname];
  832.   [IGSBlackPlayer display];
  833.   
  834.   return self;
  835. }
  836.  
  837. - setIGSHandicap: (int)h
  838. {
  839.   [IGShandicap setIntValue:h];
  840.   [IGShandicap display];
  841.  
  842.   return self;
  843. }
  844.  
  845. - setIGSKomi: (char *)k
  846. {
  847.   [IGSkomi setStringValue:k];
  848.   [IGSkomi display];
  849.  
  850.   return self;
  851. }
  852.  
  853. - updateInfo
  854. {
  855.   int oldblacksPrisoners, oldwhitesPrisoners, i, j;
  856.   unsigned char old_Board[19][19];
  857.   
  858.   if (finished && gameScored && resultsDisplayed)
  859.     {
  860.       [startButton setEnabled: NO];
  861.       [stopButton setEnabled: NO];
  862.       [passButton setEnabled: NO];
  863.       [startButton display];
  864.       [stopButton display];
  865.       [passButton display];
  866.       return self;
  867.     }
  868.   
  869.   oldblacksPrisoners = blackCaptured;
  870.   oldwhitesPrisoners = whiteCaptured;
  871.   for (i = 0; i < MAXX; i++)
  872.     for (j = 0; j < MAXX; j++)
  873.       old_Board[i][j] = p[i][j];
  874.       
  875.   examboard(opposingStone);
  876.   
  877.   if (currentStone == BLACKSTONE) {
  878.     opposingStone = BLACKSTONE;
  879.     currentStone = WHITESTONE;
  880.     [gameMessage setStringValue:"White's Turn"];
  881.   } else {
  882.     opposingStone = WHITESTONE;
  883.     currentStone = BLACKSTONE;
  884.     [gameMessage setStringValue:"Black's Turn"];
  885.   }
  886.   
  887.   [self setblacksPrisoners:blackCaptured];
  888.   [self setwhitesPrisoners:whiteCaptured];
  889.   
  890.   if (((oldblacksPrisoners != blackCaptured) ||
  891.       (oldwhitesPrisoners != whiteCaptured)))
  892.     {
  893.       [self lockFocus];
  894.       for (i = 0; i < MAXX; i++)
  895.     for (j = 0; j < MAXX; j++)
  896.       if ((old_Board[i][j] != EMPTY) && (p[i][j] == EMPTY))
  897.         {
  898.           setStoneLoc(i, j);
  899.           [self eraseStone];
  900.           [self showBackgroundPiece: i: j];
  901.         }
  902.     [self unlockFocus];
  903.   }
  904.  
  905.   if ([showHistFlag intValue])
  906.     {
  907.       NXRect tmpRect = {{floor(stoneX), floor(stoneY)},
  908.               {floor(STONEWIDTH), floor(STONEHEIGHT)}};
  909.  
  910.       [self lockFocus];
  911.       [self drawSelf:&tmpRect :0];
  912.       [self display];
  913.       [self unlockFocus];
  914.     }
  915.   
  916.   if ((blackPassed) && (opposingStone == BLACKSTONE))
  917.     [gameMessage2 setStringValue:"Black has Passed."];
  918.     
  919.   if ((whitePassed) && (opposingStone == WHITESTONE))
  920.     [gameMessage2 setStringValue:"White has Passed."];
  921.     
  922.   if ((!blackPassed) && (!whitePassed))
  923.     [gameMessage2 setStringValue:""];
  924.   
  925.   if ((blackPassed) && (whitePassed) && (!manualScoring) && (!gameScored))
  926.     {
  927.       [self lockFocus];
  928.       [[self window] flushWindow];
  929.       [gameMessage setStringValue:"Scoring Game, Please Wait"];
  930.       [gameMessage2 setStringValue:"Removing Dead Groups..."];
  931.       [self display];
  932.       [self unlockFocus];
  933.       finished = 1;
  934.       score_game();
  935. //      [self scoreGame];
  936.       manualScoring = 1;
  937.     }
  938.   if ((blackPassed) && (whitePassed) && (manualScoring) && (!gameScored))
  939.     {
  940.       [self lockFocus];
  941.       [[self window] flushWindow];
  942.       [gameMessage setStringValue:"Please remove dead groups"];
  943.       [gameMessage2 setStringValue:"When finished, press Start..."];
  944.       [self display];
  945.       [self unlockFocus];
  946.       [passButton setEnabled:NO];
  947.       [passButton display];
  948.       [stopButton setEnabled:NO];
  949.       [stopButton display];
  950.       finished = 1;
  951.       scoringGame = YES;
  952.     }
  953.  
  954.   return self;
  955.  
  956. }
  957.  
  958. - displayScoringInfo
  959. {
  960.   char s[35];
  961.   int i, j;
  962.  
  963.   if (gameScored)
  964.     {
  965.       resultsDisplayed = YES;
  966.       if (typeOfScoring == 0)
  967.     {
  968.       black_Score = (float)blackTerritory - (float)blackCaptured;
  969.       white_Score = (float)whiteTerritory - (float)whiteCaptured;
  970.       white_Score += (handicap == 0)?KOMI:0.5;
  971.       [TypeOfScoring setStringValue:"Japanese Scoring Method"];
  972.       [BlackTerrString setStringValue:"Territory"];
  973.       [WhiteTerrString setStringValue:"Territory"];
  974.       [BlackTerrValue setIntValue:blackTerritory];
  975.       [WhiteTerrValue setIntValue:whiteTerritory];
  976.       [BlackPrisonString setStringValue:"Prisoners"];
  977.       [WhitePrisonString setStringValue:"Prisoners"];
  978.       [BlackPrisonValue setIntValue:blackCaptured];
  979.       [WhitePrisonValue setIntValue:whiteCaptured];
  980.       [BlackTotalValue setFloatValue:black_Score];
  981.       [WhiteTotalValue setFloatValue:white_Score];
  982.     }
  983.       else
  984.     {
  985.       blackStones = whiteStones = 0;
  986.       for (i = 0; i < MAXX; i++)
  987.         for (j = 0; j < MAXY; j++)
  988.           {
  989.         if (p[i][j] == BLACKSTONE) blackStones++;
  990.         if (p[i][j] == WHITESTONE) whiteStones++;
  991.           }
  992.       black_Score = (float)blackTerritory + (float)blackStones;
  993.       white_Score = (float)whiteTerritory + (float)whiteStones;
  994.       white_Score += (handicap == 0)?KOMI:0.5;
  995.       [TypeOfScoring setStringValue:"Chinese Scoring Method"];
  996.       [BlackTerrString setStringValue:"Territory"];
  997.       [WhiteTerrString setStringValue:"Territory"];
  998.       [BlackTerrValue setIntValue:blackTerritory];
  999.       [WhiteTerrValue setIntValue:whiteTerritory];
  1000.       [BlackPrisonString setStringValue:"Stones"];
  1001.       [WhitePrisonString setStringValue:"Stones"];
  1002.       [BlackPrisonValue setIntValue:blackStones];
  1003.       [WhitePrisonValue setIntValue:whiteStones];
  1004.       [BlackTotalValue setFloatValue:black_Score];
  1005.       [WhiteTotalValue setFloatValue:white_Score];
  1006.     }
  1007.       if (black_Score > white_Score)
  1008.     sprintf(s, "Result:  Black wins by %3.1f points.", black_Score - white_Score);
  1009.       if (white_Score > black_Score)
  1010.     sprintf(s, "Result:  White wins by %3.1f points.", white_Score - black_Score);
  1011.       if (black_Score == white_Score)
  1012.     sprintf(s, "Result:  The game was a tie.");
  1013.       [KomiValue setFloatValue:((handicap == 0)?KOMI:0.5)];
  1014.       [GameResult setStringValue:s];
  1015.       [ScoringWindow makeKeyAndOrderFront:self];
  1016.       [gameMessage setStringValue:"Game Over"];
  1017.       [self lockFocus];
  1018.       [self display];
  1019.       [self unlockFocus];
  1020.     }
  1021.   
  1022.   return self;
  1023. }
  1024.  
  1025. - scoreGame
  1026. {
  1027.   int i, j, k, l, changes = 1, num_in_pattern;
  1028.  
  1029.   for (i = 0; i < MAXX; i++)
  1030.     for (j = 0; j < MAXY; j++)
  1031.       scoringmat[i][j] = 0;
  1032.       
  1033.   while (changes)
  1034.     {
  1035.       changes = 0;
  1036.       find_owner();
  1037.  
  1038.       for (i = 0; i < MAXX; i++)
  1039.     for (j = 0; j < MAXY; j++)
  1040.       if ((p[i][j] != 0) && (scoringmat[i][j] == 0))
  1041.         {
  1042.           if (surrounds_territory(i, j))
  1043.         {
  1044.           find_pattern_in_board(i, j);
  1045.  
  1046.           for (k = 0; k < MAXX; k++)
  1047.             for (l = 0; l < MAXY; l++)
  1048.               if (patternmat[k][l])
  1049.             scoringmat[k][l] = p[k][l];
  1050.         }
  1051.           else
  1052.         {
  1053.           find_pattern_in_board(i, j);
  1054.           set_temp_to_p();
  1055.           num_in_pattern = 0;
  1056.  
  1057.           for (k = 0; k < MAXX; k++)
  1058.             for (l = 0; l < MAXY; l++)
  1059.               if (patternmat[k][l])
  1060.             {
  1061.               p[k][l] = EMPTY;
  1062.               [self flashStone:k:l];
  1063.               num_in_pattern++;
  1064.             }
  1065.  
  1066.           find_owner();
  1067.  
  1068.           if ((ownermat[i][j] != NEUTRAL_TERR) &&
  1069.               (ownermat[i][j] != tempmat[i][j]))
  1070.             {
  1071.               if (tempmat[i][j] == BLACKSTONE)
  1072.             blackCaptured += num_in_pattern;
  1073.               else
  1074.             whiteCaptured += num_in_pattern;
  1075.               changes++;
  1076.               [self lockFocus];
  1077.               [self display];
  1078.               [self unlockFocus];
  1079.             }
  1080.           else
  1081.             {
  1082.               set_p_to_temp();
  1083.               find_owner();
  1084.             }
  1085.         }
  1086.         }
  1087.     }
  1088.  
  1089. /*  blackTerritory = 0;
  1090.   whiteTerritory = 0;
  1091.  
  1092.   [self lockFocus];
  1093.   for (i = 0; i < MAXX; i++)
  1094.     for (j = 0; j < MAXY; j++)
  1095.       {
  1096.     if (ownermat[i][j] == BLACKSTONE)
  1097.       {
  1098.         blackTerritory++;
  1099.         p[i][j] = BLACK_TERR;
  1100.       }
  1101.     if (ownermat[i][j] == WHITESTONE)
  1102.       {
  1103.         whiteTerritory++;
  1104.         p[i][j] = WHITE_TERR;
  1105.       }
  1106.     if (ownermat[i][j] == NEUTRAL_TERR)
  1107.       {
  1108.         [self flashStone:i:j];
  1109.         p[i][j] = NEUTRAL_TERR;
  1110.       }
  1111.       }
  1112.   [self unlockFocus];   */
  1113.  
  1114.   return self;
  1115. }
  1116.  
  1117. // The following methods draw the pieces.
  1118.   
  1119.   - drawBlackStone:imageRep 
  1120. {
  1121.   //    PSscale (1.0, 1.0);
  1122.   
  1123.   // First draw the shadow under the stone.
  1124.     
  1125. //    PSarc (RADIUS+SHADOWOFFSET/2, RADIUS-SHADOWOFFSET/2, 
  1126. //       RADIUS-SHADOWOFFSET, 0.0, 360.0);
  1127. //  PSsetgray (NX_DKGRAY);
  1128. //  if (NXDrawingStatus == NX_DRAWING) {
  1129. //    PSsetalpha (0.666);
  1130. //  }
  1131. //  PSfill ();
  1132.   if (NXDrawingStatus == NX_DRAWING) {
  1133.     PSsetalpha (1.0);
  1134.   }
  1135.   
  1136.   // Draw the stone.
  1137.     
  1138.     PSarc (RADIUS, RADIUS, 
  1139.        RADIUS, 0.0, 360.0);
  1140.   PSsetgray (NX_BLACK);
  1141.   PSfill ();
  1142.   
  1143.   // And the lighter & darker spots on the stone...
  1144.     
  1145.     PSarcn (RADIUS, RADIUS, 
  1146.         RADIUS-SHADOWOFFSET-3.0, 170.0, 100.0);
  1147.   PSarc (RADIUS, RADIUS, 
  1148.      RADIUS-SHADOWOFFSET-2.0, 100.0, 170.0);
  1149.   PSsetgray (NX_DKGRAY);
  1150.   PSfill ();
  1151.   PSarcn (RADIUS, RADIUS, 
  1152.       RADIUS-SHADOWOFFSET-3.0, 350.0, 280.0);
  1153.   PSarc (RADIUS, RADIUS, 
  1154.      RADIUS-SHADOWOFFSET-2.0, 280.0, 350.0);
  1155.   PSsetgray (NX_LTGRAY);
  1156.   PSfill ();
  1157.   
  1158.   return self;
  1159. }
  1160.  
  1161. - drawWhiteStone:imageRep 
  1162. {
  1163.   //    PSscale (1.0, 1.0);
  1164.   
  1165.   // First draw the shadow under the stone.
  1166.     
  1167. //    PSarc (RADIUS+SHADOWOFFSET/2, RADIUS-SHADOWOFFSET/2, 
  1168. //       RADIUS-SHADOWOFFSET, 0.0, 360.0);
  1169. //  PSsetgray (NX_DKGRAY);
  1170. //  if (NXDrawingStatus == NX_DRAWING) {
  1171. //    PSsetalpha (0.666);
  1172. //  }
  1173. //  PSfill ();
  1174.   if (NXDrawingStatus == NX_DRAWING) {
  1175.     PSsetalpha (1.0);
  1176.   }
  1177.   
  1178.   // Draw the stone.
  1179.     
  1180.     PSarc (RADIUS, RADIUS, 
  1181.        RADIUS, 0.0, 360.0);
  1182.   PSsetgray (NX_WHITE);
  1183.   PSfill ();
  1184.   
  1185.   // And the lighter & darker spots on the stone...
  1186.     
  1187.     PSarcn (RADIUS, RADIUS, 
  1188.         RADIUS-SHADOWOFFSET-3.0, 170.0, 100.0);
  1189.   PSarc (RADIUS, RADIUS, 
  1190.      RADIUS-SHADOWOFFSET-2.0, 100.0, 170.0);
  1191.   PSsetgray (NX_LTGRAY);
  1192.   PSfill ();
  1193.   PSarcn (RADIUS, RADIUS, 
  1194.       RADIUS-SHADOWOFFSET-3.0, 350.0, 280.0);
  1195.   PSarc (RADIUS, RADIUS, 
  1196.      RADIUS-SHADOWOFFSET-2.0, 280.0, 350.0);
  1197.   PSsetgray (NX_DKGRAY);
  1198.   PSfill ();
  1199.   
  1200.   return self;
  1201. }
  1202.  
  1203. - drawGrayStone:imageRep 
  1204. {
  1205.   //    PSscale (1.0, 1.0);
  1206.   
  1207.   // First draw the shadow under the stone.
  1208.     
  1209. //    PSarc (RADIUS+SHADOWOFFSET/2, RADIUS-SHADOWOFFSET/2, 
  1210. //       RADIUS-SHADOWOFFSET, 0.0, 360.0);
  1211. //  PSsetgray (NX_DKGRAY);
  1212. //  if (NXDrawingStatus == NX_DRAWING) {
  1213. //    PSsetalpha (0.666);
  1214. //  }
  1215. //  PSfill ();
  1216.   if (NXDrawingStatus == NX_DRAWING) {
  1217.     PSsetalpha (1.0);
  1218.   }
  1219.   
  1220.   // Draw the stone.
  1221.     
  1222. //    PSarc (RADIUS-SHADOWOFFSET/2, RADIUS+SHADOWOFFSET/2, 
  1223. //       RADIUS-SHADOWOFFSET, 0.0, 360.0);
  1224.     PSarc (RADIUS, RADIUS, 
  1225.        RADIUS, 0.0, 360.0);
  1226.   PSsetgray (NX_DKGRAY);
  1227.   PSfill ();
  1228.   
  1229.   // And the lighter & darker spots on the stone...
  1230.     
  1231.     PSarcn (RADIUS, RADIUS, 
  1232.         RADIUS-SHADOWOFFSET-3.0, 170.0, 100.0);
  1233.   PSarc (RADIUS, RADIUS, 
  1234.      RADIUS-SHADOWOFFSET-2.0, 100.0, 170.0);
  1235.   PSsetgray (NX_LTGRAY);
  1236.   PSfill ();
  1237.   PSarcn (RADIUS, RADIUS, 
  1238.       RADIUS-SHADOWOFFSET-3.0, 350.0, 280.0);
  1239.   PSarc (RADIUS, RADIUS, 
  1240.      RADIUS-SHADOWOFFSET-2.0, 280.0, 350.0);
  1241.   PSsetgray (NX_WHITE);
  1242.   PSfill ();
  1243.   
  1244.   return self;
  1245. }
  1246.  
  1247. - drawUpperLeft:imageRep
  1248. {
  1249.   PSsetgray(NX_BLACK);
  1250.   PSsetlinewidth(0.0);
  1251.   if (NXDrawingStatus == NX_DRAWING) {
  1252.     PSsetalpha (1.0);
  1253.   }
  1254.  
  1255.   PSnewpath();
  1256.   PSmoveto(RADIUS, RADIUS);
  1257.   PSlineto(bounds.size.width,RADIUS);
  1258.   PSmoveto(RADIUS, RADIUS);
  1259.   PSlineto(RADIUS, 0.0);
  1260.   PSmoveto(RADIUS-SHADOWOFFSET, RADIUS+SHADOWOFFSET);
  1261.   PSlineto(bounds.size.width, RADIUS+SHADOWOFFSET);
  1262.   PSmoveto(RADIUS-SHADOWOFFSET, RADIUS+SHADOWOFFSET);
  1263.   PSlineto(RADIUS-SHADOWOFFSET, 0.0);
  1264.   PSstroke();
  1265.  
  1266.   return self;
  1267. }
  1268.  
  1269. - drawUpperRight:imageRep
  1270. {
  1271.   PSsetgray(NX_BLACK);
  1272.   PSsetlinewidth(0.0);
  1273.   if (NXDrawingStatus == NX_DRAWING) {
  1274.     PSsetalpha (1.0);
  1275.   }
  1276.  
  1277.   PSnewpath();
  1278.   PSmoveto(RADIUS, RADIUS);
  1279.   PSlineto(0.0,RADIUS);
  1280.   PSmoveto(RADIUS, RADIUS);
  1281.   PSlineto(RADIUS, 0.0);
  1282.   PSmoveto(RADIUS+SHADOWOFFSET, RADIUS+SHADOWOFFSET);
  1283.   PSlineto(0.0, RADIUS+SHADOWOFFSET);
  1284.   PSmoveto(RADIUS+SHADOWOFFSET, RADIUS+SHADOWOFFSET);
  1285.   PSlineto(RADIUS+SHADOWOFFSET, 0.0);
  1286.   PSstroke();
  1287.  
  1288.   return self;
  1289. }
  1290.  
  1291. - drawLowerLeft:imageRep
  1292. {
  1293.   PSsetgray(NX_BLACK);
  1294.   PSsetlinewidth(0.0);
  1295.   if (NXDrawingStatus == NX_DRAWING) {
  1296.     PSsetalpha (1.0);
  1297.   }
  1298.  
  1299.   PSnewpath();
  1300.   PSmoveto(RADIUS, RADIUS);
  1301.   PSlineto(bounds.size.width,RADIUS);
  1302.   PSmoveto(RADIUS, RADIUS);
  1303.   PSlineto(RADIUS, bounds.size.height);
  1304.   PSmoveto(RADIUS-SHADOWOFFSET, RADIUS-SHADOWOFFSET);
  1305.   PSlineto(bounds.size.width, RADIUS-SHADOWOFFSET);
  1306.   PSmoveto(RADIUS-SHADOWOFFSET, RADIUS-SHADOWOFFSET);
  1307.   PSlineto(RADIUS-SHADOWOFFSET, bounds.size.height);
  1308.   PSstroke();
  1309.  
  1310.   return self;
  1311. }
  1312.  
  1313. - drawLowerRight:imageRep
  1314. {
  1315.   PSsetgray(NX_BLACK);
  1316.   PSsetlinewidth(0.0);
  1317.   if (NXDrawingStatus == NX_DRAWING) {
  1318.     PSsetalpha (1.0);
  1319.   }
  1320.  
  1321.   PSnewpath();
  1322.   PSmoveto(RADIUS, RADIUS);
  1323.   PSlineto(0.0,RADIUS);
  1324.   PSmoveto(RADIUS, RADIUS);
  1325.   PSlineto(RADIUS, bounds.size.height);
  1326.   PSmoveto(RADIUS+SHADOWOFFSET, RADIUS-SHADOWOFFSET);
  1327.   PSlineto(0.0, RADIUS-SHADOWOFFSET);
  1328.   PSmoveto(RADIUS+SHADOWOFFSET, RADIUS-SHADOWOFFSET);
  1329.   PSlineto(RADIUS+SHADOWOFFSET, bounds.size.height);
  1330.   PSstroke();
  1331.  
  1332.   return self;
  1333. }
  1334.  
  1335. - drawMidLeft:imageRep
  1336. {
  1337.   PSsetgray(NX_BLACK);
  1338.   PSsetlinewidth(0.0);
  1339.   if (NXDrawingStatus == NX_DRAWING) {
  1340.     PSsetalpha (1.0);
  1341.   }
  1342.  
  1343.   PSnewpath();
  1344.   PSmoveto(RADIUS, RADIUS);
  1345.   PSlineto(bounds.size.width,RADIUS);
  1346.   PSmoveto(RADIUS, bounds.size.height);
  1347.   PSlineto(RADIUS, 0.0);
  1348.   PSmoveto(RADIUS-SHADOWOFFSET, bounds.size.height);
  1349.   PSlineto(RADIUS-SHADOWOFFSET, 0.0);
  1350.   PSstroke();
  1351.  
  1352.   return self;
  1353. }
  1354.  
  1355. - drawMidRight:imageRep
  1356. {
  1357.   PSsetgray(NX_BLACK);
  1358.   PSsetlinewidth(0.0);
  1359.   if (NXDrawingStatus == NX_DRAWING) {
  1360.     PSsetalpha (1.0);
  1361.   }
  1362.  
  1363.   PSnewpath();
  1364.   PSmoveto(RADIUS, RADIUS);
  1365.   PSlineto(0.0,RADIUS);
  1366.   PSmoveto(RADIUS, bounds.size.height);
  1367.   PSlineto(RADIUS, 0.0);
  1368.   PSmoveto(RADIUS+SHADOWOFFSET, bounds.size.height);
  1369.   PSlineto(RADIUS+SHADOWOFFSET, 0.0);
  1370.   PSstroke();
  1371.  
  1372.   return self;
  1373. }
  1374.  
  1375. - drawMidTop:imageRep
  1376. {
  1377.   PSsetgray(NX_BLACK);
  1378.   PSsetlinewidth(0.0);
  1379.   if (NXDrawingStatus == NX_DRAWING) {
  1380.     PSsetalpha (1.0);
  1381.   }
  1382.  
  1383.   PSnewpath();
  1384.   PSmoveto(RADIUS, RADIUS);
  1385.   PSlineto(RADIUS,0.0);
  1386.   PSmoveto(0.0, RADIUS);
  1387.   PSlineto(bounds.size.width, RADIUS);
  1388.   PSmoveto(0.0, RADIUS+SHADOWOFFSET);
  1389.   PSlineto(bounds.size.width, RADIUS+SHADOWOFFSET);
  1390.   PSstroke();
  1391.  
  1392.   return self;
  1393. }
  1394.  
  1395. - drawMidBottom:imageRep
  1396. {
  1397.   PSsetgray(NX_BLACK);
  1398.   PSsetlinewidth(0.0);
  1399.   if (NXDrawingStatus == NX_DRAWING) {
  1400.     PSsetalpha (1.0);
  1401.   }
  1402.  
  1403.   PSnewpath();
  1404.   PSmoveto(RADIUS, RADIUS);
  1405.   PSlineto(RADIUS,bounds.size.height);
  1406.   PSmoveto(0.0, RADIUS);
  1407.   PSlineto(bounds.size.width, RADIUS);
  1408.   PSmoveto(0.0, RADIUS-SHADOWOFFSET);
  1409.   PSlineto(bounds.size.width, RADIUS-SHADOWOFFSET);
  1410.   PSstroke();
  1411.  
  1412.   return self;
  1413. }
  1414.  
  1415. - drawInnerSquare:imageRep
  1416. {
  1417.   PSsetgray(NX_BLACK);
  1418.   PSsetlinewidth(0.0);
  1419.   if (NXDrawingStatus == NX_DRAWING) {
  1420.     PSsetalpha (1.0);
  1421.   }
  1422.  
  1423.   PSnewpath();
  1424.   PSmoveto(0.0, RADIUS);
  1425.   PSlineto(bounds.size.width,RADIUS);
  1426.   PSmoveto(RADIUS, bounds.size.height);
  1427.   PSlineto(RADIUS, 0.0);
  1428.   PSstroke();
  1429.  
  1430.   return self;
  1431. }
  1432.  
  1433. - drawInnerHandicap:imageRep
  1434. {
  1435.   PSsetgray(NX_BLACK);
  1436.   PSsetlinewidth(0.0);
  1437.   if (NXDrawingStatus == NX_DRAWING) {
  1438.     PSsetalpha (1.0);
  1439.   }
  1440.  
  1441.   PSnewpath();
  1442.   PSmoveto(0.0, RADIUS);
  1443.   PSlineto(bounds.size.width,RADIUS);
  1444.   PSmoveto(RADIUS, bounds.size.height);
  1445.   PSlineto(RADIUS, 0.0);
  1446.   PSstroke();
  1447.   
  1448.   PSarc(RADIUS, RADIUS, SHADOWOFFSET, 0.0, 360.0);
  1449.   PSfill();
  1450.  
  1451.   return self;
  1452. }
  1453.  
  1454. // The following methods show or erase the stones from the board.
  1455.   
  1456.   - showBlackStone 
  1457. {
  1458.   NXRect tmpRect = {{floor(stoneX), floor(stoneY)},
  1459.               {floor(STONEWIDTH), floor(STONEHEIGHT)}};
  1460.   [blackStone composite:NX_SOVER toPoint:&tmpRect.origin];
  1461.   return self;
  1462. }
  1463.  
  1464. - showWhiteStone
  1465. {
  1466.   NXRect tmpRect = {{floor(stoneX), floor(stoneY)},
  1467.               {floor(STONEWIDTH), floor(STONEHEIGHT)}};
  1468.   [whiteStone composite:NX_SOVER toPoint:&tmpRect.origin];
  1469.   return self;
  1470. }
  1471.  
  1472. - showGrayStone
  1473. {
  1474.   NXRect tmpRect = {{floor(stoneX), floor(stoneY)},
  1475.               {floor(STONEWIDTH), floor(STONEHEIGHT)}};
  1476.   [grayStone composite:NX_SOVER toPoint:&tmpRect.origin];
  1477.   return self;
  1478. }
  1479.  
  1480. - eraseStone
  1481. {
  1482.   NXRect tmpRect = {{floor(stoneX), floor(stoneY)}, {floor(STONEWIDTH), floor(STONEHEIGHT)}};
  1483.   return [self drawBackground:&tmpRect];
  1484. }
  1485.  
  1486. // drawBackground: just draws the specified piece of the background by
  1487.   // compositing from the background image.
  1488.  
  1489.   - showBackgroundPiece: (int)x: (int)y
  1490. {
  1491.   int q;
  1492.   NXRect tmpRect = {{floor(stoneX), floor(stoneY)}, {floor(STONEWIDTH), floor(STONEHEIGHT)}};
  1493.  
  1494.   if ((x == 0) && (y == 0))
  1495.     [upperLeft composite:NX_SOVER toPoint:&tmpRect.origin];
  1496.   
  1497.   if ((x == 0) && (y == MAXY - 1))
  1498.     [lowerLeft composite:NX_SOVER toPoint:&tmpRect.origin];
  1499.   
  1500.   if ((x == MAXX - 1) && (y == 0))
  1501.     [upperRight composite:NX_SOVER toPoint:&tmpRect.origin];
  1502.   
  1503.   if ((x == MAXX - 1) && (y == MAXY - 1))
  1504.     [lowerRight composite:NX_SOVER toPoint:&tmpRect.origin];
  1505.   
  1506.   if ((x == 0) && (y > 0) && (y < MAXY - 1))
  1507.     [midLeft composite:NX_SOVER toPoint:&tmpRect.origin];
  1508.   
  1509.   if ((x == MAXX - 1) && (y > 0) && (y < MAXY - 1))
  1510.     [midRight composite:NX_SOVER toPoint:&tmpRect.origin];
  1511.   
  1512.   if ((x > 0) && (x < MAXX - 1) && (y == 0))
  1513.     [midTop composite:NX_SOVER toPoint:&tmpRect.origin];
  1514.   
  1515.   if ((x > 0) && (x < MAXX - 1) && (y == MAXY - 1))
  1516.     [midBottom composite:NX_SOVER toPoint:&tmpRect.origin];
  1517.   
  1518.   if ((x > 0) && (x < MAXX - 1) && (y > 0) && (y < MAXY - 1))
  1519.     [innerSquare composite:NX_SOVER toPoint:&tmpRect.origin];
  1520.     
  1521.   if (MAXX < 13)
  1522.     q = 2;
  1523.   else
  1524.     q = 3;
  1525.   
  1526.   if (((x == q) && (y == q)) || ((x == q) && (y == MAXY/2)) ||
  1527.       ((x == q) && (y == MAXY-q-1)) || ((x == MAXX/2) && (y == q)) ||
  1528.       ((x == MAXX/2) && (y == MAXY/2)) || ((x == MAXX/2) && (y == MAXY-q-1)) ||
  1529.       ((x == MAXX-q-1) && (y == q)) || ((x == MAXX-q-1) && (y == MAXY/2)) ||
  1530.       ((x == MAXX-q-1) && (y == MAXY-q-1)))
  1531.     [innerHandicap composite:NX_SOVER toPoint:&tmpRect.origin];
  1532.  
  1533.   return self;
  1534. }
  1535.   
  1536.   - drawBackground:(NXRect *)rect
  1537. {
  1538.   NXRect tmpRect = *rect;
  1539.   
  1540.   NX_X(&tmpRect) = floor(NX_X(&tmpRect));
  1541.   NX_Y(&tmpRect) = floor(NX_Y(&tmpRect));
  1542.   if (NXDrawingStatus == NX_DRAWING) {
  1543.     PSsetgray (NX_WHITE);
  1544.     PScompositerect (NX_X(&tmpRect), NX_Y(&tmpRect),
  1545.              NX_WIDTH(&tmpRect), NX_HEIGHT(&tmpRect), NX_COPY);
  1546.   }
  1547.   [backGround composite:NX_SOVER fromRect:&tmpRect toPoint:&tmpRect.origin];
  1548.   return self;
  1549. }
  1550.  
  1551. // drawSelf::, a method every decent View should have, redraws the game
  1552.   // in its current state. This allows us to print the game very easily.
  1553.   
  1554.   - drawSelf:(NXRect *)rects :(int)rectCount 
  1555. {
  1556.   int xcnt, ycnt;
  1557.   char s[5], specialChar;
  1558.   
  1559.   [self drawBackground:(rects ? rects : &bounds)];
  1560.  
  1561.   specialChar = 'a';
  1562.  
  1563.   for (xcnt = 0; xcnt < MAXX; xcnt++)
  1564.     {
  1565.       for (ycnt = 0; ycnt < MAXY; ycnt++)
  1566.     {
  1567.       setStoneLoc(xcnt, ycnt);
  1568.  
  1569.       switch (p[xcnt][ycnt])
  1570.         {
  1571.         case EMPTY: currentCharacter = 0;
  1572.           [self showBackgroundPiece: xcnt: ycnt];
  1573.           break;
  1574.         case WHITESTONE: [self showWhiteStone];
  1575.           if ([showHistFlag intValue] && !SmartGoGameFlag)
  1576.         {
  1577.           char s[5];
  1578.           
  1579.           [historyFont set];
  1580.           PSsetgray(NX_BLACK);
  1581.           PSmoveto(stoneX+RADIUS -
  1582.                (floor(log(hist[xcnt][ycnt]+0.5)/log(10))+1.0)*3,
  1583.                stoneY+RADIUS - 4);
  1584.           if (hist[xcnt][ycnt] > 0)
  1585.             {
  1586.               sprintf(s, "%d", hist[xcnt][ycnt]);
  1587.               PSshow(s);
  1588.             }
  1589.           else
  1590.             {
  1591.               PSmoveto(stoneX + RADIUS - 4, stoneY + RADIUS - 4);
  1592.               PSshow("H");
  1593.             }
  1594.         }
  1595.           break;
  1596.         case BLACKSTONE: [self showBlackStone];
  1597.           if ([showHistFlag intValue] && !SmartGoGameFlag)
  1598.         {
  1599.           char s[5];
  1600.  
  1601.           [historyFont set];
  1602.           PSsetgray(NX_WHITE);
  1603.           PSmoveto(stoneX+RADIUS -
  1604.                (floor(log(hist[xcnt][ycnt]+0.5)/log(10))+1.0)*3,
  1605.                stoneY+RADIUS - 4);
  1606.           if (hist[xcnt][ycnt] > 0)
  1607.             {
  1608.               sprintf(s, "%d", hist[xcnt][ycnt]);
  1609.               PSshow(s);
  1610.             }
  1611.           else
  1612.             {
  1613.               PSmoveto(stoneX + RADIUS - 4, stoneY + RADIUS - 4);
  1614.               PSshow("H");
  1615.             }
  1616.         }
  1617.           break;
  1618.         case NEUTRAL_TERR: [self showGrayStone];
  1619.           break;
  1620.         case WHITE_TERR: [self showBackgroundPiece: xcnt: ycnt];
  1621.           [whiteTerrFont set];
  1622.           PSsetgray(NX_WHITE);
  1623.           PSmoveto(stoneX+RADIUS/3, stoneY+RADIUS/3+2);
  1624.           PSshow("W");
  1625.           break;
  1626.         case BLACK_TERR: [self showBackgroundPiece: xcnt: ycnt];
  1627.           [blackTerrFont set];
  1628.           PSsetgray(NX_DKGRAY);
  1629.           PSmoveto(stoneX+RADIUS/3+1, stoneY+RADIUS/3);
  1630.           PSshow("B");
  1631.           break;
  1632.         case SPECIAL_CHAR: [self showBackgroundPiece: xcnt: ycnt];
  1633.           PSselectfont("Helvetica", 25.0);
  1634.           PSsetgray(NX_DKGRAY);
  1635.           PSmoveto(stoneX+RADIUS/3+1, stoneY+RADIUS/3);
  1636.           sprintf(s,"%c",specialChar);
  1637.           specialChar++;
  1638.           PSshow(s);
  1639.           break;
  1640.         default: currentCharacter = 0;
  1641.           [self showBackgroundPiece: xcnt: ycnt];
  1642.           break;
  1643.         }
  1644.     }
  1645.     }
  1646.  
  1647.   if ([showCoords intValue])
  1648.     {
  1649.       for (xcnt = 0; xcnt < MAXX; xcnt++)
  1650.     {
  1651.       setStoneLoc(xcnt, 0);
  1652.  
  1653.       [historyFont set];
  1654.       PSsetgray(NX_DKGRAY);
  1655.       PSmoveto(stoneX + RADIUS - 3, stoneY + RADIUS + 11);
  1656.       s[0] = 'A' + xcnt;
  1657.       if (xcnt > 7) s[0]++;
  1658.       s[1] = 0;
  1659.       PSshow(s);
  1660.  
  1661.           setStoneLoc(xcnt, MAXY - 1);
  1662.           PSmoveto(stoneX + RADIUS - 3, stoneY - 3);
  1663.       PSshow(s);
  1664.     }
  1665.       for (ycnt = 0; ycnt < MAXX; ycnt++)
  1666.     {
  1667.       setStoneLoc(0, ycnt);
  1668.  
  1669.       [historyFont set];
  1670.       PSsetgray(NX_DKGRAY);
  1671.       PSmoveto(stoneX - 4, stoneY + RADIUS - 4);
  1672.       sprintf(s, "%d", MAXY-ycnt);
  1673.       PSshow(s);
  1674.  
  1675.       setStoneLoc(MAXX - 1, ycnt);
  1676.       if (xcnt < 10)
  1677.         {
  1678.           PSmoveto(stoneX + STONEWIDTH, stoneY + RADIUS - 4);
  1679.         }
  1680.       else
  1681.         {
  1682.           PSmoveto(stoneX + STONEWIDTH - 6, stoneY + RADIUS - 4);
  1683.         }
  1684.       PSshow(s);
  1685.     }
  1686.     }
  1687.   
  1688.   return self;
  1689. }
  1690.  
  1691. - print:sender
  1692. {
  1693.   return [self printPSCode:sender];
  1694. }
  1695.  
  1696. - step
  1697. {
  1698.   NXEvent peek_ev, *get_ev;
  1699.   
  1700.   if (gameType == IGSGAME)
  1701.     {
  1702.       return self;
  1703.     }
  1704.   
  1705.   if (neitherSide)
  1706.     return self;
  1707.     
  1708.   if (((currentStone == BLACKSTONE) && (blackSide == 0)) ||
  1709.       ((currentStone == WHITESTONE) && (whiteSide == 0)))
  1710.     return self;
  1711.   
  1712.   if (bothSides) {
  1713.     while ((gameRunning) && (!finished)) {
  1714.       [self selectMove];
  1715.       NXPing();
  1716.       [self updateInfo];
  1717.  
  1718.       if( [NXApp peekNextEvent: NX_MOUSEDOWNMASK into: &peek_ev] ){
  1719.     get_ev = [NXApp getNextEvent: NX_MOUSEDOWNMASK];
  1720.     [NXApp sendEvent: get_ev];
  1721.       }
  1722.     }
  1723.   
  1724.     NXPing();
  1725.   } else {
  1726.     [passButton setEnabled: NO];
  1727.     [passButton display];
  1728.     [self selectMove];
  1729.  
  1730.     NXPing();
  1731.     [self updateInfo];
  1732.  
  1733.     NXPing();
  1734.     [passButton setEnabled: YES];
  1735.     [passButton display];
  1736.  
  1737.     NXPing();
  1738.   }
  1739.   return self;
  1740. }
  1741.  
  1742. - selectMove
  1743. {
  1744.   int i, j;
  1745.   
  1746.   NXPing();
  1747.  
  1748.   if( !bothSides )
  1749.     [stopButton setEnabled: NO];
  1750.   else
  1751.     [stopButton setEnabled: YES];
  1752.   
  1753.   genmove( &i, &j );
  1754.   if (i >= 0)
  1755.     {
  1756.       p[i][j] = currentStone;
  1757.  
  1758.       [self flashStone: i: j];
  1759.     }
  1760.  
  1761.   [self addMoveToGameMoves: currentStone: i: j];
  1762.   
  1763.   if (((i < 0) || (j < 0)) && (AGAScoring))
  1764.     {
  1765.       if (currentStone == BLACKSTONE)
  1766.         blackCaptured++;
  1767.       else
  1768.         whiteCaptured++;
  1769.     }
  1770.   
  1771.   [self selectMoveEnd];
  1772.     
  1773.   if (i >= 0)
  1774.     {
  1775.       [self lockFocus];
  1776.       if (currentStone == BLACKSTONE)
  1777.         [self showBlackStone];
  1778.       else
  1779.         [self showWhiteStone];
  1780.       [self unlockFocus];
  1781.  
  1782.       if ([playSounds intValue])
  1783.     [stoneClick play];
  1784.       NXPing();
  1785.     }
  1786.     
  1787.   NXPing();
  1788.   return self;
  1789. }
  1790.  
  1791. - selectMoveEnd
  1792. {
  1793.   NXPing();
  1794.  
  1795.   [startButton setEnabled: YES];
  1796.   [stopButton setEnabled: YES];
  1797.   NXPing();
  1798.  
  1799.   return self;
  1800. }
  1801.  
  1802. - flashStone: (int)x :(int)y
  1803. {
  1804.   
  1805.   setStoneLoc(x, y);
  1806.   
  1807.   [self lockFocus];
  1808.   [self showGrayStone];
  1809.   [self unlockFocus];
  1810.   
  1811.   return self;
  1812. }
  1813.  
  1814. - setMess1:(char *)s
  1815. {
  1816.   [gameMessage setStringValue:s];
  1817.   [gameMessage display];
  1818.  
  1819.   return self;
  1820. }
  1821.  
  1822. - setMess2:(char *)s
  1823. {
  1824.   [gameMessage2 setStringValue:s];
  1825.   [gameMessage2 display];
  1826.  
  1827.   return self;
  1828. }
  1829.  
  1830. - setblacksPrisoners:(int)bp
  1831. {
  1832.   [blacksPrisoners setIntValue:bp];
  1833.   [blacksPrisoners display];
  1834.  
  1835.   return self;
  1836. }
  1837.  
  1838. - setwhitesPrisoners:(int)wp
  1839. {
  1840.   [whitesPrisoners setIntValue:wp];
  1841.   [whitesPrisoners display];
  1842.  
  1843.   return self;
  1844. }
  1845.  
  1846.  
  1847. @end
  1848.  
  1849.